#region Namespaces

using System.Collections.Generic;
using System.IO;
using System.Xml;

#endregion

namespace Vibstudio.X4NET.Xml.Linq
{
    public class XStreamingElement
    {
        private List<object> _contents;

        public XStreamingElement(XName name)
        {
            Name = name;
        }

        public XStreamingElement(XName name, object content)
            : this(name)
        {
            Add(content);
        }

        public XStreamingElement(XName name, params object[] content)
            : this(name)
        {
            Add(content);
        }

        public XName Name { get; set; }

        internal IEnumerable<object> Contents
        {
            get { return _contents; }
        }

        public void Add(object content)
        {
            if (_contents == null)
            {
                _contents = new List<object>();
            }
            _contents.Add(content);
        }

        public void Add(params object[] content)
        {
            if (_contents == null)
            {
                _contents = new List<object>();
            }
            _contents.Add(content);
        }

        public void Save(string fileName)
        {
            using (TextWriter w = File.CreateText(fileName)) Save(w, SaveOptions.None);
        }

        public void Save(TextWriter textWriter)
        {
            Save(textWriter, SaveOptions.None);
        }

        public void Save(XmlWriter writer)
        {
            WriteTo(writer);
        }

        public void Save(string fileName, SaveOptions options)
        {
            using (TextWriter w = File.CreateText(fileName)) Save(w, options);
        }

        public void Save(TextWriter textWriter, SaveOptions options)
        {
            XmlWriterSettings s = new XmlWriterSettings();
            s.OmitXmlDeclaration = true;

            if ((options & SaveOptions.DisableFormatting) == SaveOptions.None)
            {
                s.Indent = true;
            }

            using (XmlWriter w = XmlWriter.Create(textWriter, s)) WriteTo(w);
        }

        public override string ToString()
        {
            return ToString(SaveOptions.None);
        }

        public string ToString(SaveOptions options)
        {
            StringWriter sw = new StringWriter();
            Save(sw, options);
            return sw.ToString();
        }

        public void WriteTo(XmlWriter writer)
        {
            writer.WriteStartElement(Name.LocalName, Name.Namespace.NamespaceName);
            WriteContents(_contents, writer);
            writer.WriteEndElement();
        }

        private void WriteContents(IEnumerable<object> items, XmlWriter w)
        {
            foreach (object o in XUtil.ExpandArray(items))
            {
                if (o == null)
                {
                    continue;
                }
                if (o is XStreamingElement)
                {
                    ((XStreamingElement)o).WriteTo(w);
                }
                else if (o is XNode)
                {
                    ((XNode)o).WriteTo(w);
                }
                else if (o is object[])
                {
                    WriteContents((object[])o, w);
                }
                else if (o is XAttribute)
                {
                    WriteAttribute((XAttribute)o, w);
                }
                else
                {
                    new XText(o.ToString()).WriteTo(w);
                }
            }
        }

        private void WriteAttribute(XAttribute a, XmlWriter w)
        {
            if (a.IsNamespaceDeclaration)
            {
                if (a.Name.Namespace == XNamespace.Xmlns)
                {
                    w.WriteAttributeString("xmlns", a.Name.LocalName, XNamespace.Xmlns.NamespaceName, a.Value);
                }
                else
                {
                    w.WriteAttributeString("xmlns", a.Value);
                }
            }
            else
            {
                w.WriteAttributeString(a.Name.LocalName, a.Name.Namespace.NamespaceName, a.Value);
            }
        }
    }
}